<template>
  <div>
    <div ref="map" class="map"></div>
    <form class="form-inline">
      <label for="type">测量方式 &nbsp;</label>
      <select id="type">
        <option value="LineString">长度测量</option>
        <option value="Polygon">面积测量</option>
      </select>
      &nbsp;&nbsp;&nbsp;&nbsp;
      <label for="segments">显示长度:&nbsp;</label>
      <input type="checkbox" id="segments" checked />
      &nbsp;&nbsp;&nbsp;&nbsp;
      <label for="clear">清理之前的测量:&nbsp;</label>
      <input type="checkbox" id="clear" checked />
    </form>
  </div>
</template>
  
  <script>
let {
  interaction: { Draw, Modify },
  geom: { LineString, Point },
  Map,
  View,
  layer: { Tile: TileLayer, Vector: VectorLayer },
  source: { OSM, Vector: VectorSource },
  style: { Circle: CircleStyle, Fill, RegularShape, Stroke, Style, Text },
  sphere: { getArea, getLength },
} = ol;
export default {
  mounted() {
    const typeSelect = document.getElementById("type");
    const showSegments = document.getElementById("segments");
    const clearPrevious = document.getElementById("clear");
    const style = new Style({
      fill: new Fill({
        color: "rgba(255, 255, 255, 0.2)",
      }),
      stroke: new Stroke({
        color: "rgba(0, 0, 0, 0.5)",
        lineDash: [10, 10],
        width: 2,
      }),
      image: new CircleStyle({
        radius: 5,
        stroke: new Stroke({
          color: "rgba(0, 0, 0, 0.7)",
        }),
        fill: new Fill({
          color: "rgba(255, 255, 255, 0.2)",
        }),
      }),
    });
    const labelStyle = new Style({
      text: new Text({
        font: "14px Calibri,sans-serif",
        fill: new Fill({
          color: "rgba(255, 255, 255, 1)",
        }),
        backgroundFill: new Fill({
          color: "rgba(0, 0, 0, 0.7)",
        }),
        padding: [3, 3, 3, 3],
        textBaseline: "bottom",
        offsetY: -15,
      }),
      image: new RegularShape({
        radius: 8,
        points: 3,
        angle: Math.PI,
        displacement: [0, 10],
        fill: new Fill({
          color: "rgba(0, 0, 0, 0.7)",
        }),
      }),
    });
    const tipStyle = new Style({
      text: new Text({
        font: "12px Calibri,sans-serif",
        fill: new Fill({
          color: "rgba(255, 255, 255, 1)",
        }),
        backgroundFill: new Fill({
          color: "rgba(0, 0, 0, 0.4)",
        }),
        padding: [2, 2, 2, 2],
        textAlign: "left",
        offsetX: 15,
      }),
    });
    const modifyStyle = new Style({
      image: new CircleStyle({
        radius: 5,
        stroke: new Stroke({
          color: "rgba(0, 0, 0, 0.7)",
        }),
        fill: new Fill({
          color: "rgba(0, 0, 0, 0.4)",
        }),
      }),
      text: new Text({
        text: "Drag to modify",
        font: "12px Calibri,sans-serif",
        fill: new Fill({
          color: "rgba(255, 255, 255, 1)",
        }),
        backgroundFill: new Fill({
          color: "rgba(0, 0, 0, 0.7)",
        }),
        padding: [2, 2, 2, 2],
        textAlign: "left",
        offsetX: 15,
      }),
    });
    const segmentStyle = new Style({
      text: new Text({
        font: "12px Calibri,sans-serif",
        fill: new Fill({
          color: "rgba(255, 255, 255, 1)",
        }),
        backgroundFill: new Fill({
          color: "rgba(0, 0, 0, 0.4)",
        }),
        padding: [2, 2, 2, 2],
        textBaseline: "bottom",
        offsetY: -12,
      }),
      image: new RegularShape({
        radius: 6,
        points: 3,
        angle: Math.PI,
        displacement: [0, 8],
        fill: new Fill({
          color: "rgba(0, 0, 0, 0.4)",
        }),
      }),
    });
    const segmentStyles = [segmentStyle];
    const formatLength = function (line) {
      const length = getLength(line);
      let output;
      if (length > 100) {
        output = Math.round((length / 1000) * 100) / 100 + " km";
      } else {
        output = Math.round(length * 100) / 100 + " m";
      }
      return output;
    };
    const formatArea = function (polygon) {
      const area = getArea(polygon);
      let output;
      if (area > 10000) {
        output = Math.round((area / 1000000) * 100) / 100 + " km\xB2";
      } else {
        output = Math.round(area * 100) / 100 + " m\xB2";
      }
      return output;
    };
    const raster = new TileLayer({
      source: new OSM(),
    });
    const source = new VectorSource();
    const modify = new Modify({ source: source, style: modifyStyle });
    let tipPoint;
    function styleFunction(feature, segments, drawType, tip) {
      const styles = [style];
      const geometry = feature.getGeometry();
      const type = geometry.getType();
      let point, label, line;
      if (!drawType || drawType === type) {
        if (type === "Polygon") {
          point = geometry.getInteriorPoint();
          label = formatArea(geometry);
          line = new LineString(geometry.getCoordinates()[0]);
        } else if (type === "LineString") {
          point = new Point(geometry.getLastCoordinate());
          label = formatLength(geometry);
          line = geometry;
        }
      }
      if (segments && line) {
        let count = 0;
        line.forEachSegment(function (a, b) {
          const segment = new LineString([a, b]);
          const label = formatLength(segment);
          if (segmentStyles.length - 1 < count) {
            segmentStyles.push(segmentStyle.clone());
          }
          const segmentPoint = new Point(segment.getCoordinateAt(0.5));
          segmentStyles[count].setGeometry(segmentPoint);
          segmentStyles[count].getText().setText(label);
          styles.push(segmentStyles[count]);
          count++;
        });
      }
      if (label) {
        labelStyle.setGeometry(point);
        labelStyle.getText().setText(label);
        styles.push(labelStyle);
      }
      if (
        tip &&
        type === "Point" &&
        !modify.getOverlay().getSource().getFeatures().length
      ) {
        tipPoint = geometry;
        tipStyle.getText().setText(tip);
        styles.push(tipStyle);
      }
      return styles;
    }
    const vector = new VectorLayer({
      source: source,
      style: function (feature) {
        return styleFunction(feature, showSegments.checked);
      },
    });
    const map = new Map({
      layers: [raster, vector],
      target: this.$refs.map,
      view: new View({
        center: [-11000000, 4600000],
        zoom: 15,
      }),
    });
    map.addInteraction(modify);
    let draw;
    function addInteraction() {
      const drawType = typeSelect.value;
      const activeTip =
        "Click to continue drawing the " +
        (drawType === "Polygon" ? "polygon" : "line");
      const idleTip = "Click to start measuring";
      let tip = idleTip;
      draw = new Draw({
        source: source,
        type: drawType,
        style: function (feature) {
          return styleFunction(feature, showSegments.checked, drawType, tip);
        },
      });
      draw.on("drawstart", function () {
        if (clearPrevious.checked) {
          source.clear();
        }
        modify.setActive(false);
        tip = activeTip;
      });
      draw.on("drawend", function () {
        modifyStyle.setGeometry(tipPoint);
        modify.setActive(true);
        map.once("pointermove", function () {
          modifyStyle.setGeometry();
        });
        tip = idleTip;
      });
      modify.setActive(true);
      map.addInteraction(draw);
    }
    typeSelect.onchange = function () {
      map.removeInteraction(draw);
      addInteraction();
    };
    addInteraction();
    showSegments.onchange = function () {
      vector.changed();
      draw.getOverlay().changed();
    };
  },
};
</script>